//
// RS Game Framework
// Copyright © 2010 Jedd Haberstro
// jhaberstro@gmail.com
// 
// $Id:
//

#ifndef RS_REFLECTION_CLASSBUILDER_IPP
#define RS_REFLECTION_CLASSBUILDER_IPP

#ifndef RS_REFLECTION_CLASSBUILDER_IMPLEMENTATION_GUARD
#   error "Do not include this file directly. Instead, include rs/reflection/ClassBuilder.hpp"
#endif

namespace rs
{
    namespace reflection
    {
        template< typename TClassVisitor >
        inline ClassBuilder< TClassVisitor >::ClassBuilder(Char8 const* className, Class const* parent, TClassVisitor* visitor)
        : className_(className),
          parent_(parent),
          lastAttribute_(0),
          visitor_(visitor) {
              if (visitor_ != 0) {
                  visitor_->InitializeClass(className);
              }
        }
        
        template< typename TClassVisitor >
        inline void ClassBuilder< TClassVisitor >::FinalizeClassVisitor() {
            if (visitor_) {
                visitor_->FinalizeClass();
            }
        }
        
        template< typename TClassVisitor >
        inline Char8 const* ClassBuilder< TClassVisitor >::GetClassName() const {
            return className_;
        }
                
        template< typename TClassVisitor >
        template< typename TAttribute, typename TClass >
        inline ClassBuilder< TClassVisitor >& ClassBuilder< TClassVisitor >::BindAttribute(Char8 const* name, TAttribute TClass::* attribute, Boolean visit) {
            attributes_[name] = Attribute(name, TypeFactory< TAttribute >::Create(), reinterpret_cast< UIntPtr >(&(static_cast< TClass* >(0)->*attribute)));
            lastAttribute_ = &attributes_[name];
            
            if (visit && visitor_) {
                visitor_->BindAttribute(name, attribute, *lastAttribute_);
            }
            
            return *this;
        }
                
        template< typename TClassVisitor >
        inline RsSize ClassBuilder< TClassVisitor >::GetAttributeCount() const {
            return attributes_.size();
        }
                                
        template< typename TClassVisitor >
        template< typename TFunction >
        inline ClassBuilder< TClassVisitor >& ClassBuilder< TClassVisitor >::BindMethod(Char8 const* name, TFunction method, Boolean visit) {
            typename MethodContainer::iterator inserted = methods_.insert(typename MethodContainer::value_type(name, Method(name, method)));
            
            if (visit && visitor_) {
                visitor_->BindMethod(name, method, inserted->second);
            }
            
            return *this;
        }
        
        template< typename TClassVisitor >
        template< typename TClass >
        inline ClassBuilder< TClassVisitor >& ClassBuilder< TClassVisitor >::BindDestructor() {
            destructor_ = internal::DestructorFunction< TClass >;
            return *this;
        }
                
        template< typename TClassVisitor >
        inline RsSize ClassBuilder< TClassVisitor >::GetMethodCount() const {
            return methods_.size();
        }
        
        template< typename TClassVisitor >
        inline RsSize ClassBuilder< TClassVisitor >::GetConstructorCount() const {
            return constructors_.size();
        }
        
        template< typename TClassVisitor >
        inline typename ClassBuilder< TClassVisitor >::ConstructorContainer const& ClassBuilder< TClassVisitor >::GetConstructors() const {
            return constructors_;
        }
        
        template< typename TClassVisitor >
        inline internal::Destructor ClassBuilder< TClassVisitor >::GetDestructor() const {
            return destructor_;
        }
        
        template< typename TClassVisitor >
        Attribute* ClassBuilder< TClassVisitor >::BuildAttributes() const {
            Attribute* result = new Attribute[attributes_.size()];
            RsSize i = 0;
            for (AttributeContainer::const_iterator itr = attributes_.begin(); itr != attributes_.end(); ++itr, ++i) {
                Attribute const& attrib = itr->second;
                new (result + i) Attribute(attrib);
            }
            
            return result;
        }
        
        template< typename TClassVisitor >
        Method* ClassBuilder< TClassVisitor >::BuildMethods() const {
            Method* result = new Method[methods_.size()];
            RsSize i = 0;
            for (typename MethodContainer::const_iterator itr = methods_.begin(); itr != methods_.end(); ++itr, ++i) {
                Method const& method = itr->second;
                new (result + i) Method(method);
            }
            
            return result;
        }
        
        template< typename TClassVisitor >
        inline Class const* ClassBuilder< TClassVisitor >::GetParentClass() const {
            return parent_;
        }
        
        template< typename TClassVisitor >
        inline ClassBuilder< TClassVisitor >& ClassBuilder< TClassVisitor >::operator[](AttributeProperties const& properties) {
            RS_ASSERT(lastAttribute_ != 0, "Destination attribute is null");
            lastAttribute_->SetAttributesProperties(properties);
            lastAttribute_ = 0;
            return *this;
        }
    }
}

#endif // RS_REFLECTION_CLASSBUILDER_IPP
